﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace IRC.IRepairClouds.DataLayer
{
    public partial class MultiKeyDictionary<TKey, TValue>
        :
        IMultiKeyDictionary<TKey, TValue>,
        IEnumerable<MultiKeyValuePair<TKey, TValue>>
    //ICollection<MultiKeyValuePair<TKey, TValue>>,
    //IDictionary, 
    //ICollection,
    //IEnumerable,
    //ISerializable,
    //IDeserializationCallback
    {
        //private object _syncRoot;
        private int[] buckets;
        private IEqualityComparer<TKey> comparer;
        private int keyCount;
        private int valCount;
        private KeyEntry[] keyEntries;
        private ValEntry[] valEntries;

        private int keyFreeCount;
        private int keyFreeList;

        private int valFreeCount;
        private int valFreeList;

        private KeyCollection keys;
        private ValueCollection values;
        //private SerializationInfo m_siInfo;
        private int version;
        //private const string ComparerName = "Comparer";
        //private const string HashSizeName = "HashSize";
        //private const string KeyValuePairsName = "KeyValuePairs";
        //private const string VersionName = "Version";

        public MultiKeyDictionary()
            : this(0, 0, null)
        {
        }

        public MultiKeyDictionary(IMultiKeyDictionary<TKey, TValue> dictionary)
            : this(dictionary, null)
        {
        }

        public MultiKeyDictionary(IEqualityComparer<TKey> comparer)
            : this(0, 0, comparer)
        {
        }

        public MultiKeyDictionary(int keyCapacity, int valueCapacity)
            : this(keyCapacity, valueCapacity, null)
        {
        }

        public MultiKeyDictionary(IMultiKeyDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
            : this((dictionary != null) ? dictionary.KeyCount : 0, (dictionary != null) ? dictionary.ValueCount : 0, comparer)
        {
            if (dictionary == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
            }
            foreach (MultiKeyValuePair<TKey, TValue> pair in dictionary) {
                this.Add(pair.Value, pair.Keys);
            }
        }

        public MultiKeyDictionary(int keyCapacity, int valueCapacity, IEqualityComparer<TKey> comparer)
        {
            if (keyCapacity < 0 || valueCapacity < 0) {
                throw new ArgumentOutOfRangeException();
                //ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
            }
            if (keyCapacity > 0 || valueCapacity > 0) {
                this.Initialize(keyCapacity, valueCapacity);
            }
            if (comparer == null) {
                comparer = EqualityComparer<TKey>.Default;
            }
            this.comparer = comparer;
        }

        //protected MultiKeyDictionary(SerializationInfo info, StreamingContext context)
        //{
        //    this.m_siInfo = info;
        //}

        public void Add(TValue value, params TKey[] keys)
        {
            this.Insert(keys, value, true);
        }

        public void Set(TValue value, params TKey[] keys)
        {
            this.Insert(keys, value, false);
        }

        public void Clear()
        {
            if (this.keyCount > 0) {
                for (int i = 0; i < this.buckets.Length; i++) {
                    this.buckets[i] = -1;
                }
                Array.Clear(this.keyEntries, 0, this.keyCount);
                this.keyFreeList = -1;
                this.keyCount = 0;
                this.keyFreeCount = 0;
                this.version++;
            }
            if (this.valCount > 0) {
                Array.Clear(this.valEntries, 0, this.valCount);
                this.valFreeList = -1;
                this.valCount = 0;
                this.valFreeCount = 0;
                this.version++;
            }
        }

        public bool ContainsKey(TKey key)
        {
            return (this.FindKeyEntry(key) >= 0);
        }

        public bool ContainsValue(TValue value)
        {
            if (value == null) {
                for (int i = 0; i < this.valCount; i++) {
                    if ((this.valEntries[i].valid) && (this.valEntries[i].value == null))
                        return true;
                }
            }
            else {
                EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default;
                for (int i = 0; i < this.valCount; i++) {
                    if ((this.valEntries[i].valid) && comparer.Equals(this.valEntries[i].value, value))
                        return true;
                }
            }
            return false;
        }

        //private void CopyTo(MultiKeyValuePair<TKey, TValue>[] array, int index)
        //{
        //    if (array == null) {
        //        throw new ArgumentNullException();
        //        //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
        //    }
        //    if ((index < 0) || (index > array.Length)) {
        //        throw new ArgumentOutOfRangeException();
        //        //ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
        //    }
        //    if ((array.Length - index) < this.Count) {
        //        throw new ArgumentException();
        //        //ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
        //    }
        //    int count = this.count;
        //    Entry[] entries = this.entries;
        //    for (int i = 0; i < count; i++) {
        //        if (entries[i].hashCode >= 0) {
        //            array[index++] = new MultiKeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
        //        }
        //    }
        //}

        private int FindKeyEntry(TKey key)
        {
            if (key == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            if (this.buckets != null) {
                int num = this.comparer.GetHashCode(key) & 0x7fffffff;
                for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.keyEntries[i].next) {
                    if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key, key)) {
                        return i;
                    }
                }
            }
            return -1;
        }

        private int FindValEntry(TKey key)
        {
            if (key == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            if (this.buckets != null) {
                int num = this.comparer.GetHashCode(key) & 0x7fffffff;
                for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.keyEntries[i].next) {
                    if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key, key)) {
                        return this.keyEntries[i].valueIndex;
                    }
                }
            }
            return -1;
        }

        //public Enumerator GetEnumerator()
        //{
        //    return new Enumerator((MultiKeyDictionary<TKey, TValue>)this, 2);
        //}

        //[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        //public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        //{
        //    if (info == null) {
        //        throw new ArgumentNullException();
        //        //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info);
        //    }
        //    info.AddValue("Version", this.version);
        //    info.AddValue("Comparer", this.comparer, typeof(IEqualityComparer<TKey>));
        //    info.AddValue("HashSize", (this.buckets == null) ? 0 : this.buckets.Length);
        //    if (this.buckets != null) {
        //        KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[this.Count];
        //        this.CopyTo(array, 0);
        //        info.AddValue("KeyValuePairs", array, typeof(KeyValuePair<TKey, TValue>[]));
        //    }
        //}

        private void Initialize(int keyCapacity, int valueCapacity)
        {
            int keyPrime = HashHelpers.GetPrime(keyCapacity);
            this.buckets = new int[keyPrime];
            for (int i = 0; i < this.buckets.Length; i++)
                this.buckets[i] = -1;
            this.keyEntries = new KeyEntry[keyPrime];
            this.keyFreeList = -1;

            int valuePrime = HashHelpers.GetPrime(valueCapacity);
            this.valEntries = new ValEntry[valuePrime];
            this.valFreeList = -1;
        }

        private void Insert(TKey[] keys, TValue value, bool add)
        {
            int keyFreeList;
            int valFreeList;

            if (keys == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            if (keys.Length == 0) {
                throw new ArgumentException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            if (this.buckets == null) {
                this.Initialize(0, 0);
            }

            for (int nk = 0; nk < keys.Length; nk++) {
                int valIndex = -1;
                if (this.buckets != null) {
                    int num = this.comparer.GetHashCode(keys[nk]) & 0x7fffffff;
                    for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.keyEntries[i].next) {
                        if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key, keys[nk])) {
                            if (add) {
                                throw new ArgumentException();
                                //ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
                            }
                            valIndex = this.keyEntries[i].valueIndex;
                            break;
                        }
                    }
                }
                if (valIndex >= 0) {
                    TKey[] allKeys = this.valEntries[valIndex].allKeys;
                    for (int k = 0; k < allKeys.Length; k++) {
                        var rkey = allKeys[k];
                        int num = this.comparer.GetHashCode(rkey) & 0x7fffffff;
                        int index = num % this.buckets.Length;
                        int num3 = -1;
                        for (int i = this.buckets[index]; i >= 0; i = this.keyEntries[i].next) {
                            if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key, rkey)) {
                                if (num3 < 0) {
                                    this.buckets[index] = this.keyEntries[i].next;
                                }
                                else {
                                    this.keyEntries[num3].next = this.keyEntries[i].next;
                                }
                                this.keyEntries[i].hashCode = -1;
                                this.keyEntries[i].next = this.keyFreeList;
                                this.keyEntries[i].key = default(TKey);
                                this.keyEntries[i].valueIndex = -1;
                                this.keyFreeList = i;
                                this.keyFreeCount++;
                                this.version++;
                            }
                            num3 = i;
                        }
                    }
                    this.valEntries[valIndex].allKeys = null;
                    this.valEntries[valIndex].valid = false;
                    this.valEntries[valIndex].next = this.valFreeList;
                    this.valEntries[valIndex].value = default(TValue);
                    this.valFreeList = valIndex;
                    this.valFreeCount++;
                    this.version++;
                }
            }


            var newKeys = new TKey[keys.Length];
            Array.Copy(keys, newKeys, keys.Length);

            if (this.valFreeCount > 0) {
                valFreeList = this.valFreeList;
                this.valFreeList = this.valEntries[valFreeList].next;
                this.valFreeCount--;
            }
            else {
                if (this.valCount == this.valEntries.Length)
                    this.Resize();
                valFreeList = this.valCount;
                this.valCount++;
            }

            this.valEntries[valFreeList].valid = true;
            this.valEntries[valFreeList].next = -1;

            this.valEntries[valFreeList].value = value;
            this.valEntries[valFreeList].allKeys = newKeys;

            for (int nk = 0; nk < keys.Length; nk++) {
                var key = keys[nk];

                int num = this.comparer.GetHashCode(key) & 0x7fffffff;
                int index = num % this.buckets.Length;

                //bool exist = false;
                //for (int i = this.buckets[index]; i >= 0; i = this.keyEntries[i].next) {
                //    if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key)) {
                //        if (add) {
                //            throw new ArgumentException();
                //            //ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
                //        }
                //        this.valEntries[this.keyEntries[i].valueIndex].value = value;
                //        this.valEntries[this.keyEntries[i].valueIndex].allKeys = newKeys;
                //        this.version++;

                //        //valWrapper.allKeyEntries[k] = i;
                //        exist = true;
                //        break;
                //        //return;
                //    }
                //}
                //if (exist)
                //    continue;

                if (this.keyFreeCount > 0) {
                    keyFreeList = this.keyFreeList;
                    this.keyFreeList = this.keyEntries[keyFreeList].next;
                    this.keyFreeCount--;
                }
                else {
                    if (this.keyCount == this.keyEntries.Length) {
                        this.Resize();
                        index = num % this.buckets.Length;
                    }
                    keyFreeList = this.keyCount;
                    this.keyCount++;
                }

                this.keyEntries[keyFreeList].hashCode = num;
                this.keyEntries[keyFreeList].next = this.buckets[index];
                this.keyEntries[keyFreeList].key = key;
                this.keyEntries[keyFreeList].valueIndex = valFreeList;
                this.buckets[index] = keyFreeList;
            }
            this.version++;
        }

        private static bool IsCompatibleKey(object key)
        {
            if (key == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            return (key is TKey);
        }

        //public virtual void OnDeserialization(object sender)
        //{
        //    if (this.m_siInfo != null) {
        //        int num = this.m_siInfo.GetInt32("Version");
        //        int num2 = this.m_siInfo.GetInt32("HashSize");
        //        this.comparer = (IEqualityComparer<TKey>)this.m_siInfo.GetValue("Comparer", typeof(IEqualityComparer<TKey>));
        //        if (num2 != 0) {
        //            this.buckets = new int[num2];
        //            for (int i = 0; i < this.buckets.Length; i++) {
        //                this.buckets[i] = -1;
        //            }
        //            this.entries = new Entry[num2];
        //            this.freeList = -1;
        //            KeyValuePair<TKey, TValue>[] pairArray = (KeyValuePair<TKey, TValue>[])this.m_siInfo.GetValue("KeyValuePairs", typeof(KeyValuePair<TKey, TValue>[]));
        //            if (pairArray == null) {
        //                throw new SerializationException();
        //                //ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingKeyValuePairs);
        //            }
        //            for (int j = 0; j < pairArray.Length; j++) {
        //                if (pairArray[j].Key == null) {
        //                    throw new SerializationException();
        //                    //ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_NullKey);
        //                }
        //                this.Insert(pairArray[j].Key, pairArray[j].Value, true);
        //            }
        //        }
        //        else {
        //            this.buckets = null;
        //        }
        //        this.version = num;
        //        this.m_siInfo = null;
        //    }
        //}

        public bool Remove(TKey key)
        {
            if (key == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }

            int valIndex = -1;

            if (this.buckets != null) {
                int num = this.comparer.GetHashCode(key) & 0x7fffffff;
                for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.keyEntries[i].next) {
                    if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key, key)) {
                        valIndex = this.keyEntries[i].valueIndex;
                        break;
                    }
                }
            }


            if (valIndex >= 0) {
                TKey[] allKeys = this.valEntries[valIndex].allKeys;

                for (int k = 0; k < allKeys.Length; k++) {
                    var rkey = allKeys[k];

                    int num = this.comparer.GetHashCode(rkey) & 0x7fffffff;
                    int index = num % this.buckets.Length;
                    int num3 = -1;
                    for (int i = this.buckets[index]; i >= 0; i = this.keyEntries[i].next) {
                        if ((this.keyEntries[i].hashCode == num) && this.comparer.Equals(this.keyEntries[i].key, rkey)) {
                            if (num3 < 0) {
                                this.buckets[index] = this.keyEntries[i].next;
                            }
                            else {
                                this.keyEntries[num3].next = this.keyEntries[i].next;
                            }
                            this.keyEntries[i].hashCode = -1;
                            this.keyEntries[i].next = this.keyFreeList;
                            this.keyEntries[i].key = default(TKey);
                            this.keyEntries[i].valueIndex = -1;
                            this.keyFreeList = i;
                            this.keyFreeCount++;
                            this.version++;
                            break;
                            //return true;
                        }
                        num3 = i;
                    }
                }

                this.valEntries[valIndex].allKeys = null;
                this.valEntries[valIndex].valid = false;
                this.valEntries[valIndex].next = this.valFreeList;

                this.valEntries[valIndex].value = default(TValue);
                this.valFreeList = valIndex;
                this.valFreeCount++;
                this.version++;

                return true;
            }
            return false;
        }

        private void Resize()
        {
            int keyPrime = HashHelpers.GetPrime(this.keyCount * 2);
            int[] numArray = new int[keyPrime];
            for (int i = 0; i < numArray.Length; i++)
                numArray[i] = -1;

            KeyEntry[] destinationKeyArray = new KeyEntry[keyPrime];
            Array.Copy(this.keyEntries, 0, destinationKeyArray, 0, this.keyCount);
            for (int j = 0; j < this.keyCount; j++) {
                int index = destinationKeyArray[j].hashCode % keyPrime;
                destinationKeyArray[j].next = numArray[index];
                numArray[index] = j;
            }
            this.buckets = numArray;
            this.keyEntries = destinationKeyArray;


            int valuePrime = HashHelpers.GetPrime(this.valCount * 2);
            ValEntry[] destinationValueArray = new ValEntry[valuePrime];
            Array.Copy(this.valEntries, 0, destinationValueArray, 0, this.valCount);

            this.valEntries = destinationValueArray;
        }

        //void ICollection<MultiKeyValuePair<TKey, TValue>>.Add(MultiKeyValuePair<TKey, TValue> keyValuePair)
        //{
        //    this.Add(keyValuePair.Value, keyValuePair.Key);
        //}

        //bool ICollection<MultiKeyValuePair<TKey, TValue>>.Contains(MultiKeyValuePair<TKey, TValue> keyValuePair)
        //{
        //    int index = this.FindEntry(keyValuePair.Key);
        //    return ((index >= 0) && EqualityComparer<TValue>.Default.Equals(this.entries[index].value, keyValuePair.Value));
        //}

        //void ICollection<MultiKeyValuePair<TKey, TValue>>.CopyTo(MultiKeyValuePair<TKey, TValue>[] array, int index)
        //{
        //    this.CopyTo(array, index);
        //}

        //bool ICollection<MultiKeyValuePair<TKey, TValue>>.Remove(MultiKeyValuePair<TKey, TValue> keyValuePair)
        //{
        //    int index = this.FindEntry(keyValuePair.Key);
        //    if ((index >= 0) && EqualityComparer<TValue>.Default.Equals(this.entries[index].value, keyValuePair.Value)) {
        //        this.Remove(keyValuePair.Key);
        //        return true;
        //    }
        //    return false;
        //}

        IEnumerator<MultiKeyValuePair<TKey, TValue>> IEnumerable<MultiKeyValuePair<TKey, TValue>>.GetEnumerator()
        {
            return new Enumerator((MultiKeyDictionary<TKey, TValue>)this, 2);
        }

        //void ICollection.CopyTo(Array array, int index)
        //{
        //    if (array == null) {
        //        throw new ArgumentNullException();
        //        //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
        //    }
        //    if (array.Rank != 1) {
        //        throw new ArgumentException();
        //        //ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
        //    }
        //    if (array.GetLowerBound(0) != 0) {
        //        throw new ArgumentException();
        //        //ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
        //    }
        //    if ((index < 0) || (index > array.Length)) {
        //        throw new ArgumentOutOfRangeException();
        //        //ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
        //    }
        //    if ((array.Length - index) < this.Count) {
        //        throw new ArgumentException();
        //        //ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
        //    }
        //    MultiKeyValuePair<TKey, TValue>[] pairArray = array as MultiKeyValuePair<TKey, TValue>[];
        //    if (pairArray != null) {
        //        this.CopyTo(pairArray, index);
        //    }
        //    //else if (array is DictionaryEntry[]) {
        //    //    DictionaryEntry[] entryArray = array as DictionaryEntry[];
        //    //    Entry<TKey1, TKey2, TValue>[] entries = this.entries;
        //    //    for (int i = 0; i < this.count; i++) {
        //    //        if (entries[i].hashCode >= 0) {
        //    //            entryArray[index++] = new DictionaryEntry(entries[i].key, entries[i].value);
        //    //        }
        //    //    }
        //    //}
        //    else {
        //        object[] objArray = array as object[];
        //        if (objArray == null) {
        //            throw new ArgumentException();
        //            //ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
        //        }
        //        try {
        //            int count = this.count;
        //            Entry<TKey, TValue>[] entryArray3 = this.entries;
        //            for (int j = 0; j < count; j++) {
        //                if (entryArray3[j].hashCode >= 0) {
        //                    objArray[index++] = new MultiKeyValuePair<TKey, TValue>(entryArray3[j].key, entryArray3[j].key2, entryArray3[j].value);
        //                }
        //            }
        //        }
        //        catch (ArrayTypeMismatchException) {
        //            throw new ArgumentException();
        //            //ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
        //        }
        //    }
        //}

        //void IDictionary.Add(object key1, object ke2, object value)
        //{
        //    Dictionary<TKey1, TKey2, TValue>.VerifyKey(key);
        //    Dictionary<TKey, TValue>.VerifyValueType(value);
        //    this.Add((TKey)key, (TValue)value);
        //}

        //bool IDictionary.Contains(object key)
        //{
        //    return (Dictionary<TKey, TValue>.IsCompatibleKey(key) && this.ContainsKey((TKey)key));
        //}

        //IDictionaryEnumerator IDictionary.GetEnumerator()
        //{
        //    return new Enumerator<TKey, TValue>((Dictionary<TKey, TValue>)this, 1);
        //}

        //void IDictionary.Remove(object key)
        //{
        //    if (Dictionary<TKey, TValue>.IsCompatibleKey(key)) {
        //        this.Remove((TKey)key);
        //    }
        //}

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator((MultiKeyDictionary<TKey, TValue>)this, 2);
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            int index = this.FindValEntry(key);
            if (index >= 0) {
                value = this.valEntries[index].value;
                return true;
            }
            value = default(TValue);
            return false;
        }

        private static void VerifyKey(object key)
        {
            if (key == null) {
                throw new ArgumentNullException();
                //ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            if (!(key is TKey)) {
                throw new ArgumentException();
                //ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
            }
        }

        private static void VerifyValueType(object value)
        {
            if (!(value is TValue) && ((value != null) || typeof(TValue).IsValueType)) {
                throw new ArgumentException();
                //ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));
            }
        }

        public IEqualityComparer<TKey> Comparer
        {
            get { return this.comparer; }
        }

        public int KeyCount
        {
            get { return (this.keyCount - this.keyFreeCount); }
        }

        public int ValueCount
        {
            get { return (this.valCount - this.valFreeCount); }
        }

        //public TValue this[TKey key]
        //{
        //    get
        //    {
        //        int index = this.FindEntry(key);
        //        if (index >= 0) {
        //            return this.entries[index].value.value;
        //        }
        //        throw new KeyNotFoundException();
        //        //ThrowHelper.ThrowKeyNotFoundException();
        //        //return default(TValue);
        //    }
        //    set
        //    {
        //        this.Insert(key, value, false);
        //    }
        //}

        //public KeyCollection<TKey, TValue> Keys
        //{
        //    get
        //    {
        //        if (this.keys == null) {
        //            this.keys = new KeyCollection<TKey, TValue>((Dictionary<TKey, TValue>)this);
        //        }
        //        return this.keys;
        //    }
        //}

        //bool ICollection<MultiKeyValuePair<TKey, TValue>>.IsReadOnly
        //{
        //    get
        //    {
        //        return false;
        //    }
        //}

        public ICollection<TKey> Keys
        {
            get
            {
                if (this.keys == null)
                    this.keys = new KeyCollection((MultiKeyDictionary<TKey, TValue>)this);
                return this.keys;
            }
        }

        public ICollection<TValue> Values
        {
            get
            {
                if (this.values == null)
                    this.values = new ValueCollection((MultiKeyDictionary<TKey, TValue>)this);
                return this.values;
            }
        }

        //bool ICollection.IsSynchronized
        //{
        //    get
        //    {
        //        return false;
        //    }
        //}

        //object ICollection.SyncRoot
        //{
        //    get
        //    {
        //        if (this._syncRoot == null) {
        //            Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
        //        }
        //        return this._syncRoot;
        //    }
        //}

        //bool IDictionary.IsFixedSize
        //{
        //    get
        //    {
        //        return false;
        //    }
        //}

        //bool IDictionary.IsReadOnly
        //{
        //    get
        //    {
        //        return false;
        //    }
        //}

        //object IDictionary.this[object key]
        //{
        //    get
        //    {
        //        if (Dictionary<TKey, TValue>.IsCompatibleKey(key)) {
        //            int index = this.FindEntry((TKey)key);
        //            if (index >= 0) {
        //                return this.entries[index].value;
        //            }
        //        }
        //        return null;
        //    }
        //    set
        //    {
        //        Dictionary<TKey, TValue>.VerifyKey(key);
        //        Dictionary<TKey, TValue>.VerifyValueType(value);
        //        this[(TKey)key] = (TValue)value;
        //    }
        //}

        //ICollection IDictionary.Keys
        //{
        //    get
        //    {
        //        return this.Keys;
        //    }
        //}

        //ICollection IDictionary.Values
        //{
        //    get
        //    {
        //        return this.Values;
        //    }
        //}

        //public ValueCollection<TKey, TValue> Values
        //{
        //    get
        //    {
        //        if (this.values == null) {
        //            this.values = new ValueCollection<TKey, TValue>((Dictionary<TKey, TValue>)this);
        //        }
        //        return this.values;
        //    }
        //}
    }
}
